package com.pshare.util;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.SocketTimeoutException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import net.sf.json.JSONObject;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
import org.apache.commons.httpclient.methods.DeleteMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.httpclient.methods.multipart.FilePart;
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
import org.apache.commons.httpclient.methods.multipart.Part;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

/** 
* @ClassName: HttpUtils
* @Description: 利用HttpClient封装GET/POST请求
*  
*/ 
public class HttpUtils {
	
	private static Logger log = Logger.getLogger(HttpUtils.class);    
    private static final String URL_PARAM_CONNECT_FLAG = "&";        
    private static final String EMPTY = "";    
    private static int connectionTimeOut = 25000;    
    private static int socketTimeOut = 25000;    
    private static int maxConnectionPerHost = 10;    
    private static int maxTotalConnections = 20;    
    private static MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
    private static HttpClient client= new HttpClient(connectionManager);
    private static String contentType = "application/x-www-form-urlencoded";
    
    private static String HEADER_RANGE = "Range";
	
    private HttpUtils() {}
    
    public static String getcontentType() {
		return contentType;
	}

	public static void setcontentType(String contentType) {
		HttpUtils.contentType = contentType;
	}
	
	static{  
        connectionManager.getParams().setConnectionTimeout(connectionTimeOut);  
        connectionManager.getParams().setSoTimeout(socketTimeOut);  
        connectionManager.getParams().setDefaultMaxConnectionsPerHost(maxConnectionPerHost);  
        connectionManager.getParams().setMaxTotalConnections(maxTotalConnections);  
        connectionManager.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler());
    }  
 
	public static JSONObject getJsonInUrlGet(String url, Map<String, String> params) {
		byte[] responseByte = urlGet(url, params);
		String responseStr = ByteUtils.bytes2UTF8string(responseByte);
		JSONObject json = JSONObject.fromObject(responseStr);
		return json;
	}
	
	public static JSONObject getJsonInUrlGet(String url) {
		byte[] responseByte = urlGet(url);
		String responseStr = ByteUtils.bytes2UTF8string(responseByte);
		JSONObject json = JSONObject.fromObject(responseStr);
		return json;
	}
	
	/**
	 * HTTP POST方式读取URL，得到JSON数据
	 * @param url
	 * @return JSONObject
	 */
	public static JSONObject getJsonInUrlPost(String url) {
		byte[] responseByte = urlPost(url);
		String responseStr = ByteUtils.bytes2UTF8string(responseByte);
		JSONObject json = JSONObject.fromObject(responseStr);
		return json;
	}
	
	public static JSONObject getJsonInUpload(File file, String url) {
		byte[] responseByte = postFile(file, url);
		String responseStr = ByteUtils.bytes2UTF8string(responseByte);
		JSONObject json = JSONObject.fromObject(responseStr);
		return json;
	}
	
	public static byte[] urlPost(String url) {
		return urlPost(url, new HashMap<String, String>());
	}
	
    /** 
     * <p>Title: URLPost</p> 
     * <p>Description: Post方式提交map键值对数据,默认采用UTF8编码方式</p> 
     * @param url 待请求的URL 
     * @param params 要提交的数据 
     * @return 字节流响应结果 
     * @throws IOException IO异常 
     */  
	public static byte[] urlPost(String url, Map<String, String> params) {

		byte[] response = null;
		PostMethod postMethod = null;
		try {
			postMethod = new PostMethod(url);
			postMethod.setRequestHeader("Content-Type", contentType);
			postMethod.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET,"utf-8"); 
			// 将表单的值放入postMethod中
			if(params != null && params.size() > 0) {
				Set<String> keySet = params.keySet();
				for (String key : keySet) {
					String value = params.get(key);
					postMethod.addParameter(key, value);
				}
			}
			// 执行postMethod
			int statusCode = client.executeMethod(postMethod);
			response = postMethod.getResponseBody();
			if (statusCode != HttpStatus.SC_OK) {
				log.warn("HttpStatus = " + statusCode);
			}
		} catch (HttpException e) {
			log.error("HttpClient.executeMethod(postMethod) HttpException!", e);
		} catch (IOException e) {
			log.error("HttpClient.executeMethod(postMethod) IOException!", e);
		} finally {
			if (postMethod != null) {
				postMethod.releaseConnection();
				postMethod = null;
			}
		}

		return response;
	}  
    /** 
     * <p>Title: URLPost</p> 
     * <p>Description: Post方式提交map键值对数据，自定义编码方式</p> 
     * @param url 待请求的URL 
     * @param params 要提交的数据 
     * @return 字节流响应结果 
     * @throws IOException IO异常 
     */  
	public static byte[] urlPost(String url, Map<String, String> params, String enc) {

		byte[] response = null;
		PostMethod postMethod = null;
		try {
			postMethod = new PostMethod(url);
			postMethod.setRequestHeader("Content-Type", contentType+";charset=" + enc);
			// 将表单的值放入postMethod中
			Set<String> keySet = params.keySet();
			for (String key : keySet) {
				String value = params.get(key);
				postMethod.addParameter(key, value);
			}
			// 执行postMethod
			int statusCode = client.executeMethod(postMethod);
			response = postMethod.getResponseBody();
			if (statusCode != HttpStatus.SC_OK) {
				log.warn("HttpStatus = " + statusCode);
			}
		} catch (HttpException e) {
			log.error("HttpClient.executeMethod(postMethod) HttpException!", e);
		} catch (IOException e) {
			log.error("HttpClient.executeMethod(postMethod) IOException!", e);
		} finally {
			if (postMethod != null) {
				postMethod.releaseConnection();
				postMethod = null;
			}
		}

		return response;
	}
	/** 
	* <p>Title: urlPost</p> 
	* <p>Description: Post方式提交字节流数据,默认采用UTF-8编码</p> 
	* @param url 待请求的URL地址
	* @param value Post的字符内容
	* @return 字节流响应结果
	*/ 
	public static byte[] urlPost(String url, String value) {
		String enc="UTF-8";
		byte[] response=null;
		try {
			response = urlPost(url,value.getBytes(enc));
		} catch (UnsupportedEncodingException e) {
			log.error("urlPost Exception!", e);
		}
		return response;
	}
	/** 
	* <p>Title: urlPost</p> 
	* <p>Description: Post方式提交字节流数据</p> 
	* @param url 待请求的URL地址
	* @param value Post的字符内容
	* @return 字节流响应结果
	*/ 
	public static byte[] urlPost(String url, String value,String enc) {
		byte[] response=null;
		try {
			response = urlPost(url,value.getBytes(enc));
		} catch (UnsupportedEncodingException e) {
			log.error("urlPost Exception!", e);
		}
		return response;
	}
	/** 
	* <p>Title: urlPost</p> 
	* <p>Description: Post方式提交字节流数据</p> 
	* @param url 待请求的URL地址
	* @param value post的字节流数组
	* @return 字节流响应结果
	*/ 
	public static byte[] urlPost(String url, byte[] value) {

		byte[] response = null;
		PostMethod postMethod = null;
		try {
			postMethod = new PostMethod(url);
			RequestEntity requestEntity = new ByteArrayRequestEntity(value,
					contentType);
			postMethod.setRequestEntity(requestEntity);
			// 执行postMethod
			int statusCode = client.executeMethod(postMethod);
			response = postMethod.getResponseBody();
			if (statusCode != HttpStatus.SC_OK) {
				log.warn("HttpStatus = " + statusCode);
			}
		} catch (HttpException e) {
			log.error("HttpClient.executeMethod(postMethod) HttpException!", e);
		} catch (IOException e) {
			log.error("HttpClient.executeMethod(postMethod) IOException!", e);
		} finally {
			if (postMethod != null) {
				postMethod.releaseConnection();
				postMethod = null;
			}
		}

		return response;
	}
	
	public static byte[] postJSON(String url, JSONObject obj) throws Exception {
		byte[] response = null;
		PostMethod postMethod = null;
		try {
			StringRequestEntity requestEntity = new StringRequestEntity(obj.toString(), "application/json", "UTF-8");
			postMethod = new PostMethod(url);
			postMethod.setRequestEntity(requestEntity);
			int statusCode = client.executeMethod(postMethod);
			response = postMethod.getResponseBody();
			if (statusCode != HttpStatus.SC_OK) {
				log.warn("HttpStatus = " + statusCode);
			}
		} catch (SocketTimeoutException se) {
			throw se;
		} catch (HttpException e) {
			log.error("HttpClient.executeMethod(postMethod) HttpException!", e);
			throw e;
		} catch (IOException e) {
			log.error("HttpClient.executeMethod(postMethod) IOException!", e);
			throw e;
		} finally {
			if (postMethod != null) {
				postMethod.releaseConnection();
				postMethod = null;
			}
		}

		return response;
	} 
	
	
	public static String httpPostJSON(String url, JSONObject obj) throws Exception {
		byte[] response = postJSON(url, obj);
		return ByteUtils.bytes2UTF8string(response);
	} 

    /** 
     * GET方式提交map数据 ，,默认采用UTF-8编码
     * @param url 待请求的URL 
     * @param params 要提交的map键值对数据 
     * @return 字节流响应结果 
     * @throws IOException IO异常 
     */  
	public static byte[] urlGet(String url, Map<String, String> params) {
		String enc="UTF-8";
		byte[] response = null;
		GetMethod getMethod = null;
		StringBuffer strtTotalURL = new StringBuffer(EMPTY);

		if (strtTotalURL.indexOf("?") == -1) {
			strtTotalURL.append(url).append("?").append(getUrl(params, enc));
		} else {
			strtTotalURL.append(url).append("&").append(getUrl(params, enc));
		}

		try {
			getMethod = new GetMethod(strtTotalURL.toString());
			getMethod.setRequestHeader("Content-Type", contentType);
			// 执行getMethod
			int statusCode = client.executeMethod(getMethod);
			response = getMethod.getResponseBody();
			if (statusCode != HttpStatus.SC_OK) {
				log.warn("HttpStatus = " + statusCode);
			}
		} catch (HttpException e) {
			log.error("HttpClient.executeMethod(getMethod) HttpException!", e);
		} catch (IOException e) {
			log.error("HttpClient.executeMethod(getMethod) IOException!", e);
		} finally {
			if (getMethod != null) {
				getMethod.releaseConnection();
				getMethod = null;
			}
		}

		return response;
	}
    /** 
     * GET方式提交map数据 
     * @param url 待请求的URL 
     * @param params 要提交的map键值对数据 
     * @param enc 编码 ,"UTF-8"/"GBK"
     * @return 字节流响应结果 
     * @throws IOException IO异常 
     */ 
	public static byte[] urlGet(String url, Map<String, String> params,
			String enc) {

		byte[] response = null;
		GetMethod getMethod = null;
		StringBuffer strtTotalURL = new StringBuffer(EMPTY);

		if (strtTotalURL.indexOf("?") == -1) {
			strtTotalURL.append(url).append("?").append(getUrl(params, enc));
		} else {
			strtTotalURL.append(url).append("&").append(getUrl(params, enc));
		}

		try {
			getMethod = new GetMethod(strtTotalURL.toString());
			getMethod.setRequestHeader("Content-Type", contentType);
			// 执行getMethod
			int statusCode = client.executeMethod(getMethod);
			response = getMethod.getResponseBody();
			if (statusCode != HttpStatus.SC_OK) {
				log.warn("HttpStatus = " + statusCode);
			}
		} catch (HttpException e) {
			log.error("HttpClient.executeMethod(getMethod) HttpException!", e);
		} catch (IOException e) {
			log.error("HttpClient.executeMethod(getMethod) IOException!", e);
		} finally {
			if (getMethod != null) {
				getMethod.releaseConnection();
				getMethod = null;
			}
		}

		return response;
	}
   
    /** 
     * GET方式提交数据
     * @param url 待请求的URL 
     * @return 字节流响应结果 
     * @throws IOException IO异常 
     */  
	public static byte[] urlGet(String url) {

		byte[] response = null;
		GetMethod getMethod = null;

		try {
			getMethod = new GetMethod(url);
			getMethod.setRequestHeader("Content-Type", contentType);
			// 执行getMethod
			int statusCode = client.executeMethod(getMethod);
			response = getMethod.getResponseBody();
			if (statusCode != HttpStatus.SC_OK) {
				log.warn("HttpStatus = " + statusCode);
			}

		} catch (HttpException e) {
			log.error("HttpClient.executeMethod(getMethod) HttpException!", e);
		} catch (IOException e) {
			log.error("HttpClient.executeMethod(getMethod) IOException!", e);
		} finally {
			if (getMethod != null) {
				getMethod.releaseConnection();
				getMethod = null;
			}
		}
		return response;
	}
	
	/**
	 * 上传文件接口
	 * @param file
	 * @param url
	 */
	public static byte[] postFile(File file, String url) {
		if (!file.exists()) {  
            return null;  
        } 
		byte[] response = null;
        PostMethod postMethod = new PostMethod(url);  
        try {
        	FilePart fp = new FilePart("filedata", file);
        	Part[] parts = {fp};
 
            MultipartRequestEntity mre = new MultipartRequestEntity(parts, postMethod.getParams());    // 用MulitPartRequestEntity进行包装
            postMethod.setRequestEntity(mre);  
            HttpClient client = new HttpClient();  
            client.getHttpConnectionManager().getParams().setConnectionTimeout(50000);// 设置连接时间  
            int statusCode = client.executeMethod(postMethod);  
            if (statusCode != HttpStatus.SC_OK) {
				log.warn("HttpStatus = " + statusCode);
			}
            response = postMethod.getResponseBody();
        } catch (Exception e) {  
        	log.error("HttpClient.postFile() IOException!", e);
        } finally {  
        	if (postMethod != null) {
				postMethod.releaseConnection();
				postMethod = null;
			}
        }
        return response;
	}
    
    /** 
     * 据Map生成URL字符串
     * @param map Map 
     * @param valueEnc URL编码 
     * @return URL 
     */  
    public static String getUrl(Map<String, String> map, String valueEnc) {  
        if (null == map || map.keySet().size() == 0) {  
            return (EMPTY);  
        }  
        StringBuffer url = new StringBuffer();  
        Set<String> keys = map.keySet();  
        for (Iterator<String> it = keys.iterator(); it.hasNext();) {  
            String key = it.next();  
            if (map.containsKey(key)) {  
                String val = map.get(key);  
                String str = val != null ? val : EMPTY;  
                try {  
                    str = URLEncoder.encode(str, valueEnc);  
                } catch (UnsupportedEncodingException e) {  
                    e.printStackTrace();  
                }  
                url.append(key).append("=").append(str).append(URL_PARAM_CONNECT_FLAG);  
            }  
        }  
        String strURL = EMPTY;  
        strURL = url.toString();  
        if (URL_PARAM_CONNECT_FLAG.equals(EMPTY + strURL.charAt(strURL.length() - 1))) {  
            strURL = strURL.substring(0, strURL.length() - 1);  
        }  
          
        return (strURL);  
    }  
    
    private static Object[] parseRequestRange(HttpServletRequest req) {
    	if ( StringUtils.isNotBlank(req.getHeader(HEADER_RANGE)) ) {
    		
    		Object[] ret = new Object[2];
    		
        	String rangeValue = req.getHeader(HEADER_RANGE);
        	
            //  Range:  bytes=0-801 //一般请求下载整个文件是bytes=0- 或不用这个头
            int idx = rangeValue.indexOf("=");
            if ( -1 != idx ) {
                rangeValue = rangeValue.substring(idx + 1);
            }
            idx = rangeValue.lastIndexOf("-");
            if (-1 != idx) {
                try {
                	//兼容 [-1~]这种start或者
                    String val = rangeValue.substring(0, idx);
                    
                    if ( StringUtils.isNotBlank(val) ) {
                    	ret[0] = Integer.parseInt( val );
                    }
                    if(rangeValue.length() > idx + 1){
                    	 val = rangeValue.substring(idx+1);
                         if ( StringUtils.isNotBlank(val) ) {
                         	ret[1] = Integer.parseInt( val );
                         }
                    }

                }
                catch (Exception e) {
//                    logger.error("setRange: rangeValue is [" + rangeValue +"]", e);
                	throw new RuntimeException("Http Range Error : rangeValue is [" + rangeValue +"]");
                }
            }
            
            return	ret;
    	}
    	else {
    		return	null;
    	}
    }
    
    public static int getRequestRangeBegin(HttpServletRequest req) {
    	Object[] ret = parseRequestRange(req);
    	
    	return	null == ret ? -1 : ( null == ret[0] ? -1 : (Integer)ret[0]);
    }
    
    public static int getRequestRangeEnd(HttpServletRequest req) {
    	Object[] ret = parseRequestRange(req);
    	
    	return	null == ret ? -1 : ( null == ret[1] ? -1 : (Integer)ret[1]);
    }
    
    public static String genContentRange(int begin, int end, int total ) {
    	StringBuilder sb = new StringBuilder("bytes ");
    	sb.append(begin);
    	sb.append("-");
    	sb.append(end);
    	sb.append("/");
    	sb.append(total);
    	return	sb.toString();
    }

    
	public static String doPut(String url, Map<String, Object> params) {
		System.out.println("put-url"+url);
		JSONObject obj =  new JSONObject();
		obj.putAll(params);
		String jsonStr =obj.toString();

		String resStr = null;
		HttpClient htpClient = new HttpClient();
		PutMethod putMethod = new PutMethod(url);
		putMethod.getParams().setParameter(
				HttpMethodParams.HTTP_CONTENT_CHARSET, "UTF-8");
		putMethod.setRequestHeader("Content-Type",
				"application/json; charset=utf-8");
		ByteArrayRequestEntity entity = new ByteArrayRequestEntity(
				jsonStr.getBytes(), "UTF-8");
		putMethod.setRequestEntity(entity);

		try {
			int statusCode = htpClient.executeMethod(putMethod);
			if (statusCode != HttpStatus.SC_OK) {
				resStr = putMethod.getResponseBodyAsString();
				return resStr;
//				return null;
			}
			byte[] responseBody = putMethod.getResponseBody();
			resStr = new String(responseBody, "UTF-8");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			putMethod.releaseConnection();
		}
		return resStr;
	}

	public static String doDelete(String url, Map<String, Object> params) throws UnsupportedEncodingException {
		System.out.println("delete-url"+url);
		String p = "";
		for (String param : params.keySet()) {
			p += "&" + param + "=" + params.get(param);
		}
		if (p.length() > 0) {
			p = p.substring(0);
		}

		String resStr = null;
		HttpClient htpClient = new HttpClient();
		DeleteMethod deleteMethod = new DeleteMethod(url);
//		deleteMethod.addRequestHeader(AppUtil.getCookies());
		deleteMethod.getParams().setParameter(
				HttpMethodParams.HTTP_CONTENT_CHARSET, "UTF-8");
		deleteMethod.setQueryString(p);
		try {
			int statusCode = htpClient.executeMethod(deleteMethod);
			if (statusCode != HttpStatus.SC_OK) {
				return null;
			}
			byte[] responseBody = deleteMethod.getResponseBody();
			resStr = new String(responseBody, "UTF-8");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			deleteMethod.releaseConnection();
		}
		return resStr;
	}

}
